﻿using AiMoBridge.Interface;
using AiMoWindows.CodeScripts;
using AiMoWindows.Localization;
using AiMoWindows.MainActions.Mode;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace AiMoWindows.Compiler
{
    static class Utils
    {
        public static bool PreCheck(IEnumerable<string> lines, out string error)
        {
            int i = 0;
            foreach (string line0 in lines)
            {
                i++;
                if (string.IsNullOrWhiteSpace(line0)) continue;
                string line = line0.Trim();
                int index = line.IndexOf("//");
                if (index > -1)
                {
                    line = line[..index];
                }
                if (string.IsNullOrWhiteSpace(line)) continue;

                if (line.Contains("Console.Write("))
                {
                    error = string.Format(Local.Get("Line {0}: Method {1} is not supported. Use {2} instead."), i, "Console.Write()", "Print();");
                    return false;
                }
                if (line.Contains("Console.WriteLine("))
                {
                    error = string.Format(Local.Get("Line {0}: Method {1} is not supported. Use {2} instead."), i, "Console.WriteLine()", "Print();");
                    return false;
                }
                if (line.Contains("Console.Read("))
                {
                    error = string.Format(Local.Get("Line {0}: Method {1} is not supported."), i, "Console.Read()");
                    return false;
                }
                if (line.Contains("Console.ReadKey("))
                {
                    error = string.Format(Local.Get("Line {0}: Method {1} is not supported."), i, "Console.ReadKey()");
                    return false;
                }
                if (line.Contains("Console.ReadLine("))
                {
                    error = string.Format(Local.Get("Line {0}: Method {1} is not supported."), i, "Console.ReadLine()");
                    return false;
                }
            }
            error = "";
            return true;
        }

        public static bool CheckScriptCanSendToExecutor(string assemblyPath, IExecutor? executor, ExecuterMode executerMode, ScriptComplileMode scriptMode, IDebugPrinter printer)
        {
            if ((!string.IsNullOrEmpty(assemblyPath)))
            {
                if (executor != null && executerMode != ExecuterMode.None &&
                    scriptMode != ScriptComplileMode.ExternalAssemblies)
                {
                    if (executerMode == ExecuterMode.Rhino && scriptMode == ScriptComplileMode.GrasshopperScript)
                    {
                        printer.PrintDebug(Local.Get("Cannot run Grasshopper script in Rhino as a Rhino AiMo command"));
                        return false;
                    }

                    if (executerMode == ExecuterMode.Grasshopper && scriptMode == ScriptComplileMode.RhinoScript)
                    {
                        printer.PrintDebug(Local.Get("Cannot run Rhino commmand script in Grasshopper as an AiMo C# commponent"));
                        return false;
                    }
                }
                else if (executor == null)
                {
                    printer.PrintDebug(Local.Get("AiMo is in readonly mode, there is no Rhino or Grasshopper connected. Cannot run code."));
                    return false;
                }
                return true;
            }
            else
            {
                printer.PrintDebug("Debug Error: Cannot find assembly path to excute");
                return false;
            }
        }

        public static List<string> FindAllNameSpaces(Assembly asm)
        {
            if (asm is null)
            {
                throw new ArgumentNullException("FindAllNameSpaces" + asm);
            }
            Type[] exportedTypes = asm.GetExportedTypes();
            List<string> list = new List<string>();
            if (exportedTypes == null)
            {
                return list;
            }
            Type[] array = exportedTypes;
            foreach (Type type in array)
            {
                if (type.IsVisible && (type.IsEnum || type.IsClass || type.IsInterface || type.IsValueType))
                {
                    string? namespaceString = type.Namespace;
                    if (namespaceString != null && namespaceString.Length != 0 && !list.Contains(namespaceString))
                    {
                        list.Add(namespaceString);
                    }
                }
            }
            return list;
        }
        public static string FixNewlines(string text)
        {
            if (text.Contains('\r') || text.Contains('\n'))
            {
                text = text.Replace("\r\n", "\r");
                text = text.Replace('\n', '\r');
                text = text.Replace("\r", Environment.NewLine);
            }
            return text;
        }
        public static string[] Split(string ss)
        {
            return ss.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
        }

        public static string ComputeScriptHash(ScriptSource source)
        {
            if (source == null || source.IsEmpty)
            {
                return "";
            }

            StringBuilder stringBuilder = new StringBuilder();
            source.ComputeRunningHashCode(stringBuilder);
            //File.WriteAllText(Path.Combine(@"C:\Users\wucl12\Downloads",$"{DateTime.Now:HHmmss}_test.txt"), stringBuilder.ToString());
            return CalculateStringMD5(stringBuilder.ToString());
            //MemoryStream memoryStream = new MemoryStream();
            //BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
            //source.ComputeRunningHashCode(binaryWriter);
            //checked
            //{
            //    Guid result = ToSHA_Hash(memoryStream);
            //    binaryWriter.Close();
            //    memoryStream.Dispose();
            //    return result;
            //}
        }
        public static string CalculateStringMD5(string input)
        {
            byte[] inputBytes = Encoding.UTF8.GetBytes(input);
            byte[] hashBytes = MD5.HashData(inputBytes);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hashBytes.Length; i++)
            {
                sb.Append(hashBytes[i].ToString("x2"));
            }

            return sb.ToString();
        }

        //static Guid ToSHA_Hash(Stream data)
        //{
        //    SHA1 sHA = SHA1.Create();
        //    long position = data.Position;
        //    data.Position = 0L;
        //    byte[] array = sHA.ComputeHash(data);
        //    data.Position = position;
        //    if (array.Length != 16)
        //    {
        //        Array.Resize(ref array, 16);
        //    }
        //    return new Guid(array);
        //}
    }
}
